package com.wmx.jdbc_template_app.controller;

import com.wmx.jdbc_template_app.pojo.Dept;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * Spring DataSourceUtils 数据源工具类操作演示
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2022/4/27 20:10
 */
@RestController
public class DeptController {

    /**
     * 一个操作数据库的应用，容器中肯定会有数据源的，所以可以直接从 IOC 容器中注入数据源进行使用。
     */
    @Resource
    private DataSource dataSource;

    @Resource
    private JdbcTemplate jdbcTemplate;

    /**
     * 新增部门信息
     * http://localhost:8080/dept/addData
     *
     * @param dept
     * @return
     */
    @PostMapping("dept/addData")
    @SuppressWarnings("all")
    public Object addData(@RequestBody Dept dept) throws SQLException {
        int count = 0;
        Connection conn = null;
        PreparedStatement prepareStatement = null;
        try {
            conn = DataSourceUtils.getConnection(dataSource);

            // 获取事务隔离级别
            int transactionIsolation = conn.getTransactionIsolation();
            // 确定给定的JDBC连接是否是事务性的
            boolean connectionTransactional = DataSourceUtils.isConnectionTransactional(conn, dataSource);

            // 4 (可重复读)
            System.out.println("transactionIsolation=" + transactionIsolation);
            // false
            System.out.println("connectionTransactional=" + connectionTransactional);

            // 获取预编译SQL语句对象
            String sql = "INSERT INTO dept(deptno, dname, loc) VALUES (null,?,?)";
            prepareStatement = conn.prepareStatement(sql);
            // 设置占位符参数的值(索引从1开始，表示第几个占位符)
            prepareStatement.setString(1, dept.getDname());
            prepareStatement.setString(2, dept.getLoc());

            // 执行SQL操作，返回成功插入的条数
            count = prepareStatement.executeUpdate();

            // 此时当再获取一个连接时，它们并不是同一个
            Connection connection = DataSourceUtils.getConnection(dataSource);
            // HikariProxyConnection @1522310562 wrapping com.mysql.cj.jdbc.ConnectionImpl@41c7ca3d
            System.out.println("connection=" + connection);
            // HikariProxyConnection @982737645 wrapping com.mysql.cj.jdbc.ConnectionImpl@3031c74
            System.out.println("conn=" + conn);
            DataSourceUtils.releaseConnection(connection, dataSource);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            if (prepareStatement != null && !prepareStatement.isClosed()) {
                prepareStatement.close();
            }
            // 如果连接为 null，则不执行任何操作
            DataSourceUtils.releaseConnection(conn, dataSource);
        }
        return count;
    }

    /**
     * 新增部门信息————————声明式事务管理
     * http://localhost:8080/dept/addData2
     * {"dname":"预算研发","loc":"新化"}
     *
     * @param dept
     * @return
     * @throws SQLException
     */
    @PostMapping("dept/addData2")
    @Transactional(rollbackFor = Exception.class)
    public Object addData2(@RequestBody Dept dept) throws SQLException {
        int count = 0;
        Connection conn = null;
        PreparedStatement prepareStatement = null;
        try {
            // 从 JdbcTemplate 模板中获取数据源
            DataSource dataSource = jdbcTemplate.getDataSource();
            conn = DataSourceUtils.getConnection(dataSource);

            // 获取事务隔离级别，默认是 4 (可重复读)
            int transactionIsolation = conn.getTransactionIsolation();
            // 确定给定的JDBC连接是否是事务性的————因为使用了 @Transactional注解，开启了声明式事务，所以肯定是 true.
            boolean connectionTransactional = DataSourceUtils.isConnectionTransactional(conn, this.dataSource);

            // 4 (可重复读)、true
            System.out.println("transactionIsolation=" + transactionIsolation);
            System.out.println("connectionTransactional=" + connectionTransactional);

            // 获取预编译SQL语句对象
            String sql = "INSERT INTO dept(deptno, dname, loc) VALUES (null, ? , ? )";
            prepareStatement = conn.prepareStatement(sql);
            // 设置占位符参数的值(索引从1开始，表示第几个占位符)
            prepareStatement.setString(1, dept.getDname());
            prepareStatement.setString(2, dept.getLoc());

            // 执行SQL操作，返回成功插入的条数
            count = prepareStatement.executeUpdate();

            // 此时当再获取一个连接时，它们是同一个————————因为只有同一个连接才能被同一个事务控制。
            Connection connection = DataSourceUtils.getConnection(this.dataSource);
            // HikariProxyConnection@2010103275 wrapping com.mysql.cj.jdbc.ConnectionImpl@15686ddc
            System.out.println("connection=" + connection);
            // HikariProxyConnection@2010103275 wrapping com.mysql.cj.jdbc.ConnectionImpl@15686ddc
            System.out.println("conn=" + conn);
            DataSourceUtils.releaseConnection(connection, this.dataSource);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            if (prepareStatement != null && !prepareStatement.isClosed()) {
                prepareStatement.close();
            }
            // 如果连接为 null，则不执行任何操作
            DataSourceUtils.releaseConnection(conn, dataSource);
        }
        return count;
    }


}
